
/***************************************************************************
 *   jell - library                                                        *
 *                                                                         *
 *   Copyright (C) 2008 by kuerant                                         *
 *                         <kuerant@gmail.com>                             *
 *                                                                         *
 *   This library is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU Library General Public License as       *
 *   published by the Free Software Foundation; either version 2 of the    *
 *   License, or (at your option) any later version.                       *
 *                                                                         *
 *   This library is distributed in the hope that it will be usefull, but  *
 *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      *
 *   Library General Public License for more details.                      *
 *                                                                         *
 *   You should have received a copy of the GNU Library General Public     *
 *   License along with this library; if not, write to the Free Software   *
 *   Foundation, Inc., 59 Temple Place - Suite 330, Boston,                *
 *   MA 02111-1307, USA                                                    *
 ***************************************************************************/

#include "jell/jell_allocator.hpp"

#include "jell/error.hpp"
#include "jell/jell_buf.hpp"

namespace   jell
{

    static  size_t  calcBufSize(size_t);

    ///////////////////////////////////////////////////////////////////

    JellAllocator::JellAllocator()
    {
    }

    JellAllocator::~JellAllocator()
    {
        for (pools_type::iterator it = pools.begin();
             pools.end() != it;
             ++it ) {
            pool_type*  pool = it->second;

            delete pool;
        }
        pools.clear();
    }


    ///////////////////////////////////////////////////////////////////

    Buf*
    JellAllocator::allocate(size_t size)
    {
        if (size < 1) {
            return  NULL;
        }
        size = calcBufSize( size );

        pool_type*  pool = NULL;
        pools_type::iterator    result_pool = pools.find(size);
        if (pools.end() == result_pool) {
            pool = new pool_type( size );
            pools[ size ] = pool;
        }
        else {
            pool = result_pool->second;
        }

        char*   p = pool->lease();
        Buf*    buf = new JellBuf(size, p);

        return  buf;
    }

    void
    JellAllocator::deallocate(Buf* buf)
    {
        //void*   v_p = const_cast< void * >(buf->ptr());
        //char*   p = static_cast< char * >( v_p );
        const char* c_p = static_cast< const char* >(buf->ptr());
        char*   p = const_cast< char * >( c_p );

        size_t  size = buf->capacity();

        pool_type*  pool = NULL;
        pools_type::iterator    result_pool = pools.find(size);
        if (pools.end() == result_pool) {
            // why cannot find
            throw JellException(String::format("suspicious buffer capacity(=%d).", size),
                                ERROR::BUF,
                                __LINE__, __FILE__, __FUNC__);
        }
        else {
            pool = result_pool->second;
        }

        pool->release( p );

        delete buf;
    }

    ///////////////////////////////////////////////////////////////////

    static  size_t
    calcBufSize( size_t size )
    {
        if (size < 1) {
            return  0;
        }

        size_t  factor = 1048576;
        if (size < factor) {
            factor = 65536;
        }
        size_t  mask = factor - 1;

        size_t  reminder = size & mask;
        if (0 != reminder) {
            size = (size + factor) & ~mask;
        }

        return  size;
    }

}   // namespace jell
